/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.mbds.wolf.db;

import org.mbds.wolf.exception.UserException;
import org.mbds.wolf.exception.UserExceptionReason;

/**
 *
 * @author amles_000
 */
public class DataTool {
   
    /**
     * contains
     * @param bArray
     * @param value
     * @return index
     */
    public static short contains(byte[] bArray, byte value) {
        if (bArray==null)
            return -1;
        for (short i=0;i<bArray.length;i++)
            if (bArray[i]==value)
                return i;
        return -1;
    }
    
    /**
     * addEntry
     * @param bArray
     * @param newEntry
     * @return bArray
     */
    public static byte[] addEntry(byte[] bArray, final byte newEntry) {
        if (bArray == null) {
            bArray = new byte[1];
            bArray[0] = newEntry;
            return bArray;
        } else {
            byte[] newArray = new byte[bArray.length+1];
            System.arraycopy(bArray, (short)0, newArray, (short)0, (short)bArray.length);
            newArray[bArray.length] = newEntry;
            bArray = newArray;
            return bArray;
        }
    }
    /**
     * removeEntry
     * @param bArray
     * @param entry
     * @return bArray
     */
    public static byte[] removeEntry(byte[] bArray, final byte entry) {
        if (bArray == null) {
            return bArray;
        } else {
            short index = contains(bArray, entry);
            if (index==-1)
                return bArray;
            byte[] newArray = new byte[bArray.length-1];
            short j = 0;
            for (short i=0;i<bArray.length;i++) {
                if (bArray[i]!=entry) {
                    newArray[j] = bArray[i];
                    j++;
                }
            }
            bArray = newArray;
            return bArray;
        }
    }    
    /**
     * trim
     * @param bArray
     * @return bArray 
     */
    public static byte[] trim(byte[] bArray) {
        byte[] trimed = null;
        short len = (short) bArray.length;
        for (short i=0;i<bArray.length;i++) {
            if (bArray[i]==' ')
                len--;
            if (bArray[i]!=' ')
                break;
        }
        for (short i=(short) bArray.length;i>=0;i--) {
            if (bArray[i]==' ')
                len--;
            if (bArray[i]!=' ')
                break;
        }
        if (len!=bArray.length) {
            trimed = new byte[len];
            len = 0;
            boolean stop = false;
            for (short i=0;i<bArray.length;i++) {
                if (len>=trimed.length)
                    break;
                if (bArray[i]!=' ' && !stop) 
                    stop=true;
                if (stop) {
                    trimed[len] = bArray[i];
                    len++;
                }
            }
        }
        return trimed;
    }  
        
    /**
     * containsId
     * @param id
     * @param dataArray
     * @return index
     */
    public static short containsId(short id, final AtomicData[] dataArray) {
        for (short i=0;i<dataArray.length;i++) {
            if (dataArray[i]!=null && dataArray[i].id()==id) {
                return i;
            }
        }
        return -1;
    }
    
    /**
     * 
     * @param containsValue
     * @param dataArray
     * @return index
     * @throws UserException 
     */
    public static short containsValue(final byte[] value, 
            final AtomicData[] dataArray) throws UserException {
        if (value==null)
            UserException.throwIt(UserExceptionReason.INVALID_ARGUMENT_EXCEPTION);
        for (short i=0;i<dataArray.length;i++) {
            if (dataArray[i]!=null  && dataArray[i].value!=null) {
                if (((byte[]) dataArray[i].value()).length!=value.length)
                    break;
                boolean used = true;
                for (short j=0; j<((byte[]) dataArray[i].value()).length;j++) {
                    if (((byte[]) dataArray[i].value())[j]!=value[j]) {
                        used = false;
                        break;
                    }
                }
                if (used)
                    return i;
            }
        }
        return -1;
    }
    
    /**
     * equals
     * @param bArray1
     * @param bArray2
     * @return boolean
     */
    public static boolean equals(byte[] bArray1, byte[] bArray2) {
        boolean equal = false;
        if (bArray1 == null && bArray2 == null) {
            equal = true;
        } else if (bArray1 != null && bArray2 != null) {
            if (bArray1.length == bArray2.length) {
                for (short j = 0; j < bArray2.length; j++) {
                    if (bArray1[j] != bArray2[j]) {
                        equal = false;
                        break;
                    }
                }
            }
        } 
        return equal;
    }
    
    /**
     * whereEquals
     * @param value
     * @param data
     * @return equalValues
     * @throws UserException 
     */
    public static AtomicData[] whereEquals(final byte[] value, 
            final AtomicData[] data) throws UserException {
        AtomicData[] equalValues = new AtomicData[data.length];
        short nb = 0;
        for (short i=0;i<data.length;i++) {
            boolean equal = false;
            if (data[i]!=null) {
                equal = equals(data[i].value(), value);
            }
            if (equal) {
                equalValues[nb] = data[i];
                nb++;
            }
        }
        if (nb<equalValues.length) {
            try {
                decreaseAtomicDataArray(equalValues, nb);
            } catch (UserException e) {
                throw e;
            }
        }
        return equalValues;
    }
   
    /**
     * increaseAtomicDataArray
     * @param AtomicData array
     * @param inc
     * @param maxSize
     * @return new AtomicData array
     * @throws UserException 
     */
    public static AtomicData[] increaseAtomicDataArray(AtomicData[] array, 
            final short inc, final short maxSize) throws UserException {
        if (array.length + inc > maxSize) {
            UserException.throwIt(UserExceptionReason.ARRAY_INDEX_OUT_OF_BOUND);
        }
        AtomicData[] newArray = new AtomicData[(short) (array.length + inc)];
        for (short i = 0; i < array.length; i++) {
            newArray[i] = array[i];
        }
        array = newArray;
        return array;
    }
    /**
     * decreaseAtomicDataArray
     * @param array
     * @param newSize
     * @return new AtomicData array
     * @throws UserException 
     */
    public static AtomicData[] decreaseAtomicDataArray(AtomicData[] array, 
            final short newSize) throws UserException {
        if (newSize > array.length) {
            UserException.throwIt(UserExceptionReason.ARRAY_INDEX_OUT_OF_BOUND);
        }
        AtomicData[] newArray = new AtomicData[newSize];
        for (short i = 0; i < newSize; i++) {
            newArray[i] = array[i];
        }
        array = newArray;
        return array;
    }
    
    /**
     * sortAtomicDataArray
     * @param array
     * @return sortedArray
     * @throws UserException 
     */
    public static AtomicData[] sortAtomicDataArray(final AtomicData[] array) throws UserException {
        AtomicData[] sortedArray = new AtomicData[array.length];
        byte comp = 0;
        for(short i=0;i<array.length-1;i++) {
            if (array[i] == null || array[i+1] == null) {
                if (array[i] == null) 
                    comp = -1;
                else 
                    comp = 1;
            } else if (array[i].value == null) {
                comp = -1;
            }  else if (array[i+1].value == null) {
                comp = 1;
            }  else
                try {
                    comp = arrayCompare(array[i].value(), (short)0, array[i+1].value(), (short)0, (short)(array[i].value().length
                            >array[i+1].value().length?array[i+1].value().length:array[i].value().length));
                    if (comp == 0) {
                        if (array[i].value().length<=array[i+1].value().length)
                            comp = -1;
                        else
                            comp = 1;
                    }
                } catch (ArrayIndexOutOfBoundsException e) {
                    UserException.throwIt(UserExceptionReason.ARRAY_INDEX_OUT_OF_BOUND);
                } catch (NullPointerException e) {
                    UserException.throwIt(UserExceptionReason.INVALID_ARGUMENT_EXCEPTION);
                }
            if (comp == 1) {
                permutAtomicDataArray(sortedArray, i, (short) (i+1));
            }
	}
        return sortedArray;
    }
    
    /**
     * arrayCompare
     * @param bArray1
     * @param start1
     * @param bArray2
     * @param start2
     * @param nbBytes
     * @return
     */
    public static byte arrayCompare(byte[] bArray1, short start1, byte[] bArray2, short start2, short nbBytes) 
    		throws ArrayIndexOutOfBoundsException, NullPointerException {
    	if (bArray1==null || bArray2==null) {
    			throw new NullPointerException();
    	}
    	if (start1<0 || start2<0 || nbBytes<=0) {
    		throw new ArrayIndexOutOfBoundsException();
    	}
    	short len = (short) (bArray1.length<=bArray2.length?bArray1.length:bArray2.length);
    	for (short i=0; i<len; i++) {
    		if (bArray1[i]<bArray2[i])
    			return -1;
    		if (bArray1[i]>bArray2[i])
    			return 1;
    	}
    	if (bArray1.length<len)
    		return -1;
    	if (bArray1.length>len)
    		return 1;
    	return 0;
    }
    
    
    /**
     * permutAtomicDataArray
     * @param array
     * @param index1
     * @param index2
     * @return permuted array
     */
    public static AtomicData[] permutAtomicDataArray(AtomicData[] array, short index1, short index2) {
        AtomicData temp = array[index2];
        array[index2] = array[index1];
        array[index1] = temp;
        return array;
    }
}
